module PIEDecoder(
	input	Clk,
	input	Rst,
	input	Din,
	output [7:0] Dout,
	output	D_en,
	output	F_en
);

	parameter IDLE = 3'b000;
	parameter O = 3'b001;
	parameter OO = 3'b010;
	parameter OOL = 3'b011;
	parameter OOLO = 3'b100;
	parameter OOLOL = 3'b101;
	parameter OOLOLL = 3'b110;
	parameter OOLOLLL = 3'b111;
	
	reg [3:0] current_state;
	reg isworking;
	
	reg [4:0] pie_clk_cnt;
	reg pie_clk;
	reg [7:0] byte_store;
	wire getSOF;
	wire getEOF;
	
	reg data;
	reg [2:0] bit_cnt;
	wire [2:0] bit_cnt_full;
	wire bit_cnt_up;
	reg [3:0] byte_cnt;
	wire byte_cnt_up;
	reg dout_1;
	reg dout_2;
	
	always @(posedge Clk or negedge Rst) begin
		if(!Rst) begin
			current_state <= IDLE;
			pie_clk_cnt <= 0;
			pie_clk <= 0;
			isworking <= 0;
			data <= 0;
			bit_cnt <= 0;
			byte_cnt <= 0;
			byte_store <= 0;
			dout_1 <= 0;
			dout_2 <= 0;
		end
		else begin
			//pie_clk
			if(pie_clk_cnt == 4) begin
				pie_clk_cnt <= 0;
				pie_clk <= 1;
			end
			else begin
				pie_clk_cnt <= pie_clk_cnt + 1;
				pie_clk <= 0;
			end
			//when to work? is working?
			if((!isworking)&getSOF)
				isworking <= 1;
			else if(isworking&getEOF)
				isworking <= 0;
			else
				isworking <= isworking;
			//FSM
			case(current_state)
				IDLE: if(pie_clk&(!Din)) current_state <= O; else current_state <= current_state;
				O: if(pie_clk&(!Din)) current_state <= OO; else if(pie_clk&Din) current_state <= IDLE; else current_state <= current_state;
				OO: if(pie_clk&Din) current_state <= OOL; else current_state <= current_state;
				OOL: if(pie_clk&(!Din)) current_state <= OOLO; else if(pie_clk&Din) current_state <= IDLE; else current_state <= current_state;
				OOLO: if(pie_clk&Din) current_state <= OOLOL; else if(pie_clk&(!Din)) current_state <= OO; else current_state <= current_state;
				OOLOL: if(pie_clk&Din) current_state <= OOLOLL; else if(pie_clk&(!Din)) current_state <= O; else current_state <= current_state;
				OOLOLL: if(pie_clk&Din) current_state <= OOLOLLL; else if(pie_clk&(!Din)) current_state <= O; else current_state <= current_state;
				OOLOLLL: if(pie_clk&(!Din)) current_state <= O; else if(pie_clk&Din) current_state <= IDLE; else current_state <= current_state;
				default: current_state <= IDLE;
			endcase
			//bit counter
			if(pie_clk & isworking & (!bit_cnt_up))
				bit_cnt <= bit_cnt + 1;
			else if(bit_cnt_up)
				bit_cnt <= 0;
			else if(!isworking)
				bit_cnt <= 0;
			else
				bit_cnt <= bit_cnt;
			//byte counter
			if(bit_cnt_up & !(byte_cnt_up))
				byte_cnt <= byte_cnt + 1;
			else if(byte_cnt_up)
				byte_cnt <= 0;
			else if(!isworking)
				byte_cnt <= 0;
			else
				byte_cnt <= byte_cnt;
			//save the current input data
			if(bit_cnt_up) begin
				data <= Din;
				byte_store[7-byte_cnt] <= Din;
			end
			else begin
				data <= data;
				byte_store <= byte_store;
			end
			//Dout delay two Clk
			if(isworking) begin
				dout_1 <= byte_cnt_up;
				dout_2 <= dout_1;
			end
			else begin
				dout_1 <= dout_1;
				dout_2 <= dout_2;
			end
		end
	end
	
	//combinational logic to find SOF and EOF
	assign getSOF = (current_state==OOLOLLL) & (!Din) & (pie_clk);
	assign getEOF = (current_state==OOL) & (!Din) & (pie_clk);
	
	//combinational logic to generate count-up signal
	assign bit_cnt_up = (bit_cnt == bit_cnt_full) & isworking & pie_clk;
	assign byte_cnt_up = (byte_cnt == 7) & bit_cnt_up;
	
	//combinational logic to control the bit_cnt_full
	assign bit_cnt_full = (data)? 3:1;
	
	//output signal
	assign Dout = byte_store;
	assign D_en = dout_2;
	assign F_en = getSOF;

endmodule